package com.company.project.controller;

import com.company.project.config.ThreadPoolComponent;
import com.company.project.model.TopologyHistory;
import com.company.project.service.NetworkService;
import com.company.project.vo.req.AttackRecordVo;
import com.company.project.vo.resp.Response;
import com.company.project.vo.resp.ServerTrafficVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/network")
@Api(tags = "网络拓扑模块")
@Slf4j
public class NetworkController {
    @Autowired
    private NetworkService networkService;

    @Autowired
    private ThreadPoolComponent threadPoolComponent;

    private static final String TEMP_DIR = "F:\\GDProject\\v1.4\\springboot-manager\\src\\main\\resources\\temp\\";
    private static final String DEFAULT_TOPOLOGY_FILE = "F:\\GDProject\\v1.4\\springboot-manager\\src\\main\\resources\\topology.json";

    public NetworkController() {
        // 确保 temp 文件夹存在
        File tempDir = new File(TEMP_DIR);
        if (!tempDir.exists()) {
            boolean created = tempDir.mkdirs();
            if (created) {
                log.info("Created temp directory: {}", TEMP_DIR);
            } else {
                log.error("Failed to create temp directory: {}", TEMP_DIR);
            }
        } else {
            log.info("Temp directory already exists: {}", TEMP_DIR);
            // 检查目录权限
            if (!tempDir.canWrite()) {
                log.error("Temp directory is not writable: {}", TEMP_DIR);
            }
        }
    }
    /**
     * 用户上传文件并加载拓扑
     */
    @ApiOperation(value = "用户上传拓扑")
    @PostMapping("/load")
    public Response<String> loadTopology(@RequestPart("file") MultipartFile file) {
        log.info("load Received file: {}", file.getOriginalFilename());
        try {
            if (file.isEmpty()) {
                return Response.error("上传的文件为空");
            }

            // 确保temp目录存在
            File tempDir = new File(TEMP_DIR);
            if (!tempDir.exists()) {
                boolean created = tempDir.mkdirs();
                if (!created) {
                    log.error("Failed to create temp directory: {}", TEMP_DIR);
                    return Response.error("Failed to create temp directory");
                }
            }

            String fileHash = calculateFileHash(file);
            File existingFile = new File(TEMP_DIR + fileHash + ".json");
            String originalFilename = file.getOriginalFilename();

            if (existingFile.exists()) {
                log.info("File already exists, loading from existing file: {}", existingFile.getAbsolutePath());
                networkService.loadTopology(existingFile.getAbsolutePath(), originalFilename, fileHash);
                return Response.success("Topology loaded successfully from existing file!");
            }

            File tempFile = new File(TEMP_DIR + fileHash + ".json");
            try {
                file.transferTo(tempFile);
                log.info("File saved to: {}", tempFile.getAbsolutePath());
            } catch (IOException e) {
                log.error("Failed to save file: {}", e.getMessage());
                return Response.error("Failed to save file: " + e.getMessage());
            }
            networkService.loadTopology(tempFile.getAbsolutePath(), originalFilename, fileHash);
            return Response.success("Topology loaded successfully and saved to temp folder!");
        } catch (Exception e) {
            log.error("Error loading topology: {}", e.getMessage(), e);
            return Response.error("Error: " + e.getMessage());
        }
    }

    /**
     * 默认加载 resources/topology.json 文件
     */
    @ApiOperation(value = "默认加载拓扑")
    @GetMapping("/defaultLoad")
    public Response<String> defaultLoadTopology() {
        log.info("defaultLoadTopology");
        try {
            // 确保默认拓扑文件存在
            File defaultFile = new File(DEFAULT_TOPOLOGY_FILE);
            if (!defaultFile.exists()) {
                log.error("Default topology file not found: {}", DEFAULT_TOPOLOGY_FILE);
                return Response.error("Default topology file not found");
            }

            // 计算文件哈希值
            String fileHash = calculateFileHash(defaultFile);
            log.info("Default topology file hash: {}", fileHash);

            // 默认拓扑也应该加入历史记录
            networkService.loadTopology(DEFAULT_TOPOLOGY_FILE, "default_topology.json", fileHash);
            log.info("Default topology loaded successfully!");
            return Response.success("Default topology loaded successfully!");
        } catch (Exception e) {
            log.error("defaultLoadTopologyError: {}", e.getMessage(), e);
            return Response.error("Error: " + e.getMessage());
        }
    }
    /**
     * 获取历史拓扑列表
     */
    @ApiOperation(value = "获取历史拓扑列表")
    @GetMapping("/topology/history")
    public Response<List<Map<String, String>>> getTopologyHistory() {
        log.info("getTopologyHistory");
        try {
            List<TopologyHistory> historyList = networkService.getTopologyHistory();
            List<Map<String, String>> result = historyList.stream()
                .map(history -> {
                    Map<String, String> item = new HashMap<>();
                    item.put("id", history.getId());
                    item.put("name", history.getName());
                    item.put("createTime", history.getCreateTime().toString());
                    return item;
                })
                .collect(Collectors.toList());
            log.info("historyList: {}", result);
            return Response.success("获取历史拓扑成功", result);
        } catch (Exception e) {
            log.error("Error: " + e.getMessage());
            return Response.error("Error: " + e.getMessage());
        }
    }

    /**
     * 加载指定的历史拓扑
     */
    @ApiOperation(value = "加载历史拓扑")
    @PostMapping("/topology/load/{id}")
    public Response<Map<String, Object>> loadHistoryTopology(@PathVariable String id) {
        log.info("loadHistoryTopology {}", id);
        try {
            Map<String, Object> topologyData = networkService.loadHistoryTopology(id);
            log.info("topologyData: {}", topologyData);
            return Response.success("历史拓扑加载成功", topologyData);
        } catch (Exception e) {
            log.error("Error: " + e.getMessage());
            return Response.error("Error: " + e.getMessage());
        }
    }
    /**
     * 清理网络
     */
    @ApiOperation(value = "清理网络")
    @DeleteMapping("/clear")
    public Response<String> clearNetwork() {
        log.info("clearNetwork");
        try {
            networkService.clearNetwork();
            log.info("Network cleared successfully!");
            return Response.success("Network cleared successfully!");
        } catch (Exception e) {
            log.error("Error: " + e.getMessage());
            return Response.error("Error: " + e.getMessage());
        }
    }

    @GetMapping("/attackerCount")
    public Response<Integer> getAttackerCount() {
        log.info("getAttackerCount");
        try {
            int count = networkService.getAttackerCount();
            log.info("count: {}", count);
            return Response.success("Attacker count retrieved successfully!", count);
        } catch (Exception e) {
            log.error("Error: " + e.getMessage());
            return Response.error("Error: " + e.getMessage());
        }
    }

    @GetMapping("/serverCount")
    public Response<Integer> getServerCount() {
        log.info("getServerCount");
        try {
            int count = networkService.getServerCount();
            log.info("count: {}", count);
            return Response.success("Server count retrieved successfully!", count);
        } catch (Exception e) {
            return Response.error("Error: " + e.getMessage());
        }
    }

    /**
     * 执行攻击
     */
    @ApiOperation(value = "执行攻击")
    @PostMapping("/attack")
    public Response<String> attack(@RequestBody AttackRecordVo attackRecordvo) {
        try {
            networkService.executeAttack(attackRecordvo);
            return Response.success("Attack executed successfully!");
        } catch (Exception e) {
            return Response.error("Error: " + e.getMessage());
        }
    }

    /**
     * 实时获取服务器流量信息
     */
    @ApiOperation(value = "实时获取服务器流量信息")
    @PostMapping("/serverTraffic")
    public Response<ServerTrafficVo> getServerInfo(@RequestBody String serverName) {
        log.info("getServerInfo {}", serverName);
        try {
            // 去除可能的引号和空白字符
            serverName = serverName.trim();
            if (serverName.startsWith("\"") && serverName.endsWith("\"")) {
                serverName = serverName.substring(1, serverName.length() - 1);
            }

            log.info("Processing server name: {}", serverName);
            String trafficInfo = networkService.getServerTrafficInfo(serverName);
            long rxBytes = 0;
            long txBytes = 0;
            String[] parts = trafficInfo.split(", ");
            for (String part : parts) {
                if (part.startsWith("RX bytes:")) {
                    rxBytes = Long.parseLong(part.split(":")[1].trim());
                } else if (part.startsWith("TX bytes:")) {
                    txBytes = Long.parseLong(part.split(":")[1].trim());
                }
            }
            ServerTrafficVo serverTrafficVo = new ServerTrafficVo(serverName, rxBytes, txBytes);
            log.info("serverTrafficVo: {}", serverTrafficVo);
            return Response.success("Server traffic retrieved successfully!", serverTrafficVo);
        } catch (Exception e) {
            log.error("Error getting server traffic: {}", e.getMessage(), e);
            return Response.error("Error: " + e.getMessage());
        }
    }

    /**
     * 验证攻击是否有效
     */
    @ApiOperation(value = "验证攻击是否有效")
    @PostMapping("/verifyAttack")
    public Response<String> verifyAttack(@RequestBody Map<String, String> requestBody) {
        String attackerName = requestBody.get("attackerName");
        String targetName = requestBody.get("targetName");

        log.info("verifyAttack - attacker: {}, target: {}", attackerName, targetName);

        if (attackerName == null || attackerName.isEmpty()) {
            return Response.error("Attacker name cannot be empty");
        }

        if (targetName == null || targetName.isEmpty()) {
            return Response.error("Target name cannot be empty");
        }
        try {
            log.info("Processing attack verification from attacker: {} to target: {}", attackerName, targetName);
            String verificationResult = networkService.verifyAttack(attackerName, targetName);
            return Response.success("Attack verification completed successfully!", verificationResult);
        } catch (Exception e) {
            log.error("Error verifying attack: {}", e.getMessage(), e);
            return Response.error("Error: " + e.getMessage());
        }
    }

    /**
     * 计算文件的哈希值（SHA-256）
     */
    private String calculateFileHash(MultipartFile file) throws IOException {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] fileBytes = file.getBytes();
            byte[] hashBytes = digest.digest(fileBytes);
            StringBuilder hexString = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (Exception e) {
            throw new IOException("Failed to calculate file hash", e);
        }
    }
    private String calculateFileHash(File file) throws IOException {
        // 使用 try-with-resources 语句自动管理输入流的关闭
        try (java.io.InputStream inputStream = java.nio.file.Files.newInputStream(file.toPath())) {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] buffer = new byte[8192];
            int bytesRead;
            // 循环读取文件内容并更新摘要
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                digest.update(buffer, 0, bytesRead);
            }
            byte[] hashBytes = digest.digest();
            StringBuilder hexString = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (Exception e) {
            // 抛出包装后的异常
            throw new IOException("Failed to calculate file hash", e);
        }
    }
}
